﻿using SafeLoad.NControl.Assist;
using SafeLoad.NControl.Converter;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace SafeLoad.NControl
{
    /// <summary>
    /// NPipeLine.xaml 的交互逻辑
    /// </summary>
    public partial class NPipeLine : UserControl
    {
        #region Contructor

        /// <summary>
        /// 实例化一个管道对象
        /// </summary>
        public NPipeLine()
        {
            InitializeComponent();
            UpdateRightDirectionBinding();
            UpdateLeftDirectionBinding();
        }

        private DoubleAnimation offectDoubleAnimation = null;

        #endregion

        #region Property Dependency

        #region LeftDirection Property

        /// <summary>
        /// 设置左边的方向
        /// </summary>
        public NPipeDirection LeftDirection
        {
            get { return (NPipeDirection)GetValue(LeftDirectionProperty); }
            set { SetValue(LeftDirectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LeftDirection.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LeftDirectionProperty =
            DependencyProperty.Register("LeftDirection", typeof(NPipeDirection), typeof(NPipeLine),
                new PropertyMetadata(NPipeDirection.None, new PropertyChangedCallback(LeftDirectionPropertyChangedCallback)));

        public static void LeftDirectionPropertyChangedCallback(System.Windows.DependencyObject dependency, System.Windows.DependencyPropertyChangedEventArgs e)
        {
            NPipeLine pipeLine = (NPipeLine)dependency;
            pipeLine.UpdateLeftDirectionBinding();
        }

        public void UpdateLeftDirectionBinding()
        {
            BindingOperations.ClearBinding(ellipe1, Canvas.TopProperty);
            if (LeftDirection == NPipeDirection.Down)
            {
                canvas1.Visibility = Visibility.Visible;
                Binding binding = new Binding();
                binding.Source = grid1;
                binding.Path = new PropertyPath("ActualHeight");
                binding.Converter = new MultiplesValueConverter();
                binding.ConverterParameter = 0;
                ellipe1.SetBinding(Canvas.TopProperty, binding);
            }
            else if (LeftDirection == NPipeDirection.Up)
            {
                canvas1.Visibility = Visibility.Visible;
                Binding binding = new Binding();
                binding.Source = grid1;
                binding.Path = new PropertyPath("ActualHeight");
                binding.Converter = new MultiplesValueConverter();
                binding.ConverterParameter = -1;
                ellipe1.SetBinding(Canvas.TopProperty, binding);
            }
            else
            {
                canvas1.Visibility = Visibility.Collapsed;
            }
            UpdatePathData();
        }

        #endregion

        #region RightDirection Property

        /// <summary>
        /// 设置右边的方向
        /// </summary>
        public NPipeDirection RightDirection
        {
            get { return (NPipeDirection)GetValue(RightDirectionProperty); }
            set { SetValue(RightDirectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LeftDirection.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RightDirectionProperty =
            DependencyProperty.Register("RightDirection", typeof(NPipeDirection), typeof(NPipeLine),
                new PropertyMetadata(NPipeDirection.None, new PropertyChangedCallback(RightDirectionPropertyChangedCallback)));

        public static void RightDirectionPropertyChangedCallback(System.Windows.DependencyObject dependency, System.Windows.DependencyPropertyChangedEventArgs e)
        {
            NPipeLine pipeLine = (NPipeLine)dependency;
            pipeLine.UpdateRightDirectionBinding();
        }

        public void UpdateRightDirectionBinding()
        {
            BindingOperations.ClearBinding(ellipe2, Canvas.TopProperty);
            if (RightDirection == NPipeDirection.Down)
            {
                canvas2.Visibility = Visibility.Visible;
                Binding binding = new Binding();
                binding.Source = grid1;
                binding.Path = new PropertyPath("ActualHeight");
                binding.Converter = new MultiplesValueConverter();
                binding.ConverterParameter = 0;
                ellipe2.SetBinding(Canvas.TopProperty, binding);
            }
            else if (RightDirection == NPipeDirection.Up)
            {
                canvas2.Visibility = Visibility.Visible;
                Binding binding = new Binding();
                binding.Source = grid1;
                binding.Path = new PropertyPath("ActualHeight");
                binding.Converter = new MultiplesValueConverter();
                binding.ConverterParameter = -1;
                ellipe2.SetBinding(Canvas.TopProperty, binding);
            }
            else
            {
                canvas2.Visibility = Visibility.Collapsed;
            }
            UpdatePathData();
        }

        #endregion

        #region PipeLineActive Property

        public bool PipeLineActive
        {
            get { return (bool)GetValue(PipeLineActiveProperty); }
            set { SetValue(PipeLineActiveProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PipeLineActive.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PipeLineActiveProperty =
            DependencyProperty.Register("PipeLineActive", typeof(bool), typeof(NPipeLine), new PropertyMetadata(false, new PropertyChangedCallback(PropertyChangedCallback)));

        #endregion

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            UpdatePathData();
            base.OnRenderSizeChanged(sizeInfo);
        }

        #region LineOffect Property

        public double LineOffect
        {
            get { return (double)GetValue(LineOffectProperty); }
            set { SetValue(LineOffectProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LineOffect.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LineOffectProperty =
            DependencyProperty.Register("LineOffect", typeof(double), typeof(NPipeLine), new PropertyMetadata(0d));


        public void UpdatePathData()
        {
            var g = new StreamGeometry();
            using (StreamGeometryContext context = g.Open())
            {
                if (LeftDirection == NPipeDirection.Down)
                {
                    context.BeginFigure(new Point(ActualHeight / 2, ActualHeight), false, false);
                    context.ArcTo(new Point(ActualHeight, ActualHeight / 2), new Size(ActualHeight / 2, ActualHeight / 2), 0, false, SweepDirection.Clockwise, true, false);
                }
                else if (LeftDirection == NPipeDirection.Up)
                {
                    context.BeginFigure(new Point(ActualHeight / 2, 0), false, false);
                    context.ArcTo(new Point(ActualHeight, ActualHeight / 2), new Size(ActualHeight / 2, ActualHeight / 2), 0, false, SweepDirection.Counterclockwise, true, false);
                }
                else
                {
                    context.BeginFigure(new Point(0, ActualHeight / 2), false, false);
                    context.LineTo(new Point(ActualHeight, ActualHeight / 2), true, false);
                }

                context.LineTo(new Point(ActualWidth - ActualHeight, ActualHeight / 2), true, false);

                if (RightDirection == NPipeDirection.Down)
                {
                    context.ArcTo(new Point(ActualWidth - ActualHeight / 2, ActualHeight), new Size(ActualHeight / 2, ActualHeight / 2), 0, false, SweepDirection.Clockwise, true, false);
                }
                else if (RightDirection == NPipeDirection.Up)
                {
                    context.ArcTo(new Point(ActualWidth - ActualHeight / 2, 0), new Size(ActualHeight / 2, ActualHeight / 2), 0, false, SweepDirection.Counterclockwise, true, false);
                }
                else
                {
                    context.LineTo(new Point(ActualWidth, ActualHeight / 2), true, false);
                }

            }
            path1.Data = g;
        }

        #endregion

        #region MoveSpeed Property

        /// <summary>
        /// 获取或设置流动的速度
        /// </summary>
        public double MoveSpeed
        {
            get 
			{ 
				return (double)GetValue(MoveSpeedProperty);
			}
            set
			{ 
				SetValue(MoveSpeedProperty, value); 
			}
        }

        // Using a DependencyProperty as the backing store for MoveSpeed.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MoveSpeedProperty =
            DependencyProperty.Register("MoveSpeed", typeof(double), typeof(NPipeLine), new PropertyMetadata(0.3d, new PropertyChangedCallback(PropertyChangedCallback)));

        public static void PropertyChangedCallback(DependencyObject dependency, DependencyPropertyChangedEventArgs e)
        {
            NPipeLine pipeLine = (NPipeLine)dependency;
            pipeLine.MoveSpeedOrActiveChanged();
        }

        private void MoveSpeedOrActiveChanged()
        {
            if (!PipeLineActive)
            {
                //取消动画
                if (offectDoubleAnimation != null)
                {
                    BeginAnimation(LineOffectProperty, null);
                    offectDoubleAnimation = null;
                }
                return;
            }

            if (Math.Abs(MoveSpeed) < 0.001)
            {
                //MoveSpeed 等于0 , 停止动画
                if (offectDoubleAnimation != null)
                {
                    BeginAnimation(LineOffectProperty, null);
                    offectDoubleAnimation = null;
                }
            }
            else if (MoveSpeed > 0)
            {
                offectDoubleAnimation = new DoubleAnimation(0d, -10d, TimeSpan.FromMilliseconds(300 / MoveSpeed));
                offectDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
                BeginAnimation(LineOffectProperty, offectDoubleAnimation);
                
            }
            else
            {
                offectDoubleAnimation = new DoubleAnimation(0d, 10d, TimeSpan.FromMilliseconds(300 / Math.Abs(MoveSpeed)));
                offectDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
                BeginAnimation(LineOffectProperty, offectDoubleAnimation);
            }
        }

        #endregion

        #region PipeLineWidth Property

        /// <summary>
        /// 管道活动状态时的中心线的线条宽度
        /// </summary>
        public int PipeLineWidth
        {
            get { return (int)GetValue(PipeLineWidthProperty); }
            set 
			{ 
				SetValue(PipeLineWidthProperty, value);
			}
        }

        // Using a DependencyProperty as the backing store for PipeLineWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PipeLineWidthProperty =
            DependencyProperty.Register("PipeLineWidth", typeof(int), typeof(NPipeLine), new PropertyMetadata(2));

        #endregion

        #region PipeLineColor Property
        /// <summary>
        /// 容量的颜色
        /// </summary>
        public static readonly DependencyProperty PipeLineColorProperty = DependencyProperty.Register("PipeLineColor",
                typeof(Color), typeof(NPipeLine), new PropertyMetadata(Colors.LightGray));
        public Color PipeLineColor
        {
            get { return (Color)GetValue(PipeLineColorProperty); }
            set
			{ 
				SetValue(PipeLineColorProperty, value);
			}
        }
        #endregion

        #endregion
    }
}
